Make focus rectangles optional
authorMatthias Clasen <mclasen@redhat.com>
Wed, 10 Aug 2011 14:00:38 +0000 (16:00 +0200)
committerMatthias Clasen <mclasen@redhat.com>
Wed, 10 Aug 2011 14:34:20 +0000 (16:34 +0200)
This commit introduces a new setting, gtk-visible-focus, backed
by the Gtk/VisibleFocus X setting. Its three values control how
focus rectangles are displayed.

'always' is equivalent to the traditional GTK+ behaviour of always
rendering focus rectangles.

'never' does what it says, and is intended for keyboardless
situations, e.g. tablets.

'automatic' hides focus rectangles initially, until the user
interacts with the keyboard, at which point focus rectangles
become visible.

https://bugzilla.gnome.org/show_bug.cgi?id=649567

25 files changed:
docs/reference/gtk/gtk3-sections.txt
gdk/x11/gdksettings.c
gtk/gtk.symbols
gtk/gtkbutton.c
gtk/gtkcalendar.c
gtk/gtkcellarea.c
gtk/gtkcheckbutton.c
gtk/gtkcolorsel.c
gtk/gtkentry.c
gtk/gtkexpander.c
gtk/gtkhsv.c
gtk/gtkiconview.c
gtk/gtklabel.c
gtk/gtkmain.c
gtk/gtknotebook.c
gtk/gtkrange.c
gtk/gtksettings.c
gtk/gtkswitch.c
gtk/gtktextview.c
gtk/gtktrayicon-x11.c
gtk/gtktreeview.c
gtk/gtkwidget.c
gtk/gtkwidget.h
gtk/gtkwindow.c
gtk/gtkwindow.h

index e1a8a848471394be4a2668df29a818e7d968cf85..3677068d94d41fc035c279630016686e272659ea 100644 (file)
@@ -5111,6 +5111,7 @@ gtk_widget_unset_state_flags
 gtk_widget_get_state_flags
 gtk_widget_has_default
 gtk_widget_has_focus
+gtk_widget_has_visible_focus
 gtk_widget_has_grab
 gtk_widget_has_rc_style
 gtk_widget_is_drawable
@@ -5293,6 +5294,8 @@ gtk_window_get_opacity
 gtk_window_set_opacity
 gtk_window_get_mnemonics_visible
 gtk_window_set_mnemonics_visible
+gtk_window_get_focus_visible
+gtk_window_set_focus_visible
 gtk_window_set_has_resize_grip
 gtk_window_get_has_resize_grip
 gtk_window_resize_grip_is_visible
index 8edb7dc8f48e2916d828b14366bf08b817b4f949..7a876f03c28aa3cf8c6f5aa47209c3f6171fabdf 100644 (file)
@@ -80,7 +80,8 @@ static const char gdk_settings_names[] =
   "Net/EnableInputFeedbackSounds\0" "gtk-enable-input-feedback-sounds\0"
   "Net/EnableEventSounds\0"   "gtk-enable-event-sounds\0"
   "Gtk/CursorBlinkTimeout\0"  "gtk-cursor-blink-timeout\0"
-  "Gtk/AutoMnemonics\0"       "gtk-auto-mnemonics\0";
+  "Gtk/AutoMnemonics\0"       "gtk-auto-mnemonics\0"
+  "Gtk/VisibleFocus\0"        "gtk-visible-focus\0";
 
 
 static const struct
@@ -133,5 +134,6 @@ static const struct
   { 1573, 1603 },
   { 1636, 1658 },
   { 1682, 1705 },
-  { 1730, 1748 }
+  { 1730, 1748 },
+  { 1767, 1784 }
 };
index 4325f2f12f0a50f35d10aa2af760c6f65ee50b63..06878dd8230e478d72c699d63adc639b9f7b33b9 100644 (file)
@@ -3725,6 +3725,7 @@ gtk_window_get_deletable
 gtk_window_get_destroy_with_parent
 gtk_window_get_focus
 gtk_window_get_focus_on_map
+gtk_window_get_focus_visible
 gtk_window_get_gravity
 gtk_window_get_group
 gtk_window_get_has_resize_grip
@@ -3791,6 +3792,7 @@ gtk_window_set_deletable
 gtk_window_set_destroy_with_parent
 gtk_window_set_focus
 gtk_window_set_focus_on_map
+gtk_window_set_focus_visible
 gtk_window_set_geometry_hints
 gtk_window_set_gravity
 gtk_window_set_has_resize_grip
index 6b967846fb966b42be77899a86b45b34064c6622..aa3fe63b18e8ec845e11f95a194a72f98f20c433 100644 (file)
@@ -1570,6 +1570,7 @@ _gtk_button_paint (GtkButton          *button,
   gint focus_pad;
   GtkAllocation allocation;
   GtkStyleContext *context;
+  gboolean draw_focus;
 
   widget = GTK_WIDGET (button);
   context = gtk_widget_get_style_context (widget);
@@ -1605,8 +1606,11 @@ _gtk_button_paint (GtkButton          *button,
       width -= default_outside_border.left + default_outside_border.right;
       height -= default_outside_border.top + default_outside_border.bottom;
     }
-   
-  if (!interior_focus && gtk_widget_has_focus (widget))
+
+  draw_focus = gtk_widget_has_visible_focus (widget);
+
+
+  if (!interior_focus && draw_focus)
     {
       x += focus_width + focus_pad;
       y += focus_width + focus_pad;
@@ -1623,7 +1627,7 @@ _gtk_button_paint (GtkButton          *button,
                        x, y, width, height);
     }
 
-  if (gtk_widget_has_focus (widget))
+  if (draw_focus)
     {
       gint child_displacement_x;
       gint child_displacement_y;
@@ -1658,8 +1662,7 @@ _gtk_button_paint (GtkButton          *button,
           y += child_displacement_y;
         }
 
-      gtk_render_focus (context, cr,
-                       x, y, width, height);
+      gtk_render_focus (context, cr, x, y, width, height);
     }
 
   gtk_style_context_restore (context);
index c8eac513687236c4cd303b33a7cf598a7a5020e7..cff79bf5642a2419e4df542c4970fe6961700b8a 100644 (file)
@@ -2710,8 +2710,8 @@ calendar_paint_day (GtkCalendar *calendar,
       pango_cairo_show_layout (cr, layout);
     }
 
-  if (gtk_widget_has_focus (widget)
-      && priv->focus_row == row && priv->focus_col == col)
+  if (gtk_widget_has_visible_focus (widget) &&
+      priv->focus_row == row && priv->focus_col == col)
     gtk_render_focus (context, cr,
                       day_rect.x, day_rect.y,
                       day_rect.width, day_rect.height);
index 099c4e58b670017236616d79e045eaa2537be1c0..7ef6cc936481740ca428190f53825da54f666aa2 100644 (file)
@@ -1204,6 +1204,9 @@ gtk_cell_area_real_render (GtkCellArea          *area,
   if (gtk_cell_area_get_edited_cell (area))
     render_data.paint_focus = FALSE;
 
+  if (!gtk_widget_has_visible_focus (widget))
+    render_data.paint_focus = FALSE;
+
   /* If no cell can activate but the caller wants focus painted,
    * then we paint focus around all cells */
   if ((flags & GTK_CELL_RENDERER_FOCUSED) != 0 && paint_focus &&
index 3b8b950b82bacf5d943f30127918609f05e3f786..7982e7fe5356f17d4c7a49aa085bbe60f71c7a42 100644 (file)
@@ -172,26 +172,27 @@ gtk_check_button_paint (GtkWidget    *widget,
                        cairo_t      *cr)
 {
   GtkCheckButton *check_button = GTK_CHECK_BUTTON (widget);
-  gint border_width;
-  gint interior_focus;
-  gint focus_width;
-  gint focus_pad;
-      
-  gtk_widget_style_get (widget,
-                        "interior-focus", &interior_focus,
-                        "focus-line-width", &focus_width,
-                        "focus-padding", &focus_pad,
-                        NULL);
 
   gtk_check_button_draw_indicator (check_button, cr);
 
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
-  if (gtk_widget_has_focus (widget))
+  if (gtk_widget_has_visible_focus (widget))
     {
       GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
       GtkStyleContext *context;
       GtkStateFlags state;
       GtkAllocation allocation;
+      gint border_width;
+      gint interior_focus;
+      gint focus_width;
+      gint focus_pad;
+
+      border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+
+      gtk_widget_style_get (widget,
+                            "interior-focus", &interior_focus,
+                            "focus-line-width", &focus_width,
+                            "focus-padding", &focus_pad,
+                            NULL);
 
       gtk_widget_get_allocation (widget, &allocation);
       context = gtk_widget_get_style_context (widget);
index a098799cf2dfc5942e2565ac130f52ef5ddaed3b..c83279a335cd585f0ad984eb79ec12adc43076a6 100644 (file)
@@ -1131,7 +1131,7 @@ palette_draw (GtkWidget *drawing_area,
   gdk_cairo_set_source_rgba (cr, &color);
   cairo_paint (cr);
 
-  if (gtk_widget_has_focus (drawing_area))
+  if (gtk_widget_has_visible_focus (drawing_area))
     {
       set_focus_line_attributes (drawing_area, cr, &focus_width);
 
index f5b42d33c5c71bcddf7639320a7f645537f270c1..89d8f6f629c417beb455f6092f7fae4bff011992 100644 (file)
@@ -3438,7 +3438,7 @@ gtk_entry_draw_frame (GtkWidget       *widget,
 
   gtk_entry_draw_progress (widget, context, cr);
 
-  if (gtk_widget_has_focus (widget) && !priv->interior_focus)
+  if (gtk_widget_has_visible_focus (widget) && !priv->interior_focus)
     {
       x -= priv->focus_width;
       y -= priv->focus_width;
index ef926ebf7a52d24c4bcd433dda9bf482f5f03aeb..4485454222e748158062b3307ff24fdc84c68f51 100644 (file)
@@ -1016,7 +1016,7 @@ gtk_expander_draw (GtkWidget *widget,
 
   gtk_expander_paint (expander, cr);
 
-  if (gtk_widget_has_focus (widget))
+  if (gtk_widget_has_visible_focus (widget))
     gtk_expander_paint_focus (expander, cr);
 
   GTK_WIDGET_CLASS (gtk_expander_parent_class)->draw (widget, cr);
index ea133aaa58408f972c7919d981d0f89cef646128..6266b4f17d040f2f3f11fe0db4e990c59985d3a4 100644 (file)
@@ -862,13 +862,6 @@ paint_ring (GtkHSV  *hsv,
   cairo_surface_t *source;
   cairo_t *source_cr;
   gint stride;
-  gint focus_width;
-  gint focus_pad;
-
-  gtk_widget_style_get (widget,
-                        "focus-line-width", &focus_width,
-                        "focus-padding", &focus_pad,
-                        NULL);
 
   width = gtk_widget_get_allocated_width (widget);
   height = gtk_widget_get_allocated_height (widget);
@@ -993,8 +986,9 @@ get_color (gdouble h,
 
 /* Paints the HSV triangle */
 static void
-paint_triangle (GtkHSV      *hsv,
-                cairo_t     *cr)
+paint_triangle (GtkHSV   *hsv,
+                cairo_t  *cr,
+                gboolean  draw_focus)
 {
   GtkHSVPrivate *priv = hsv->priv;
   GtkWidget *widget = GTK_WIDGET (hsv);
@@ -1182,8 +1176,7 @@ paint_triangle (GtkHSV      *hsv,
   
   /* Draw focus outline */
 
-  if (gtk_widget_has_focus (widget) &&
-      !priv->focus_on_ring)
+  if (draw_focus && !priv->focus_on_ring)
     {
       gint focus_width;
       gint focus_pad;
@@ -1205,16 +1198,20 @@ paint_triangle (GtkHSV      *hsv,
 
 /* Paints the contents of the HSV color selector */
 static gboolean
-gtk_hsv_draw (GtkWidget      *widget,
-              cairo_t        *cr)
+gtk_hsv_draw (GtkWidget *widget,
+              cairo_t   *cr)
 {
   GtkHSV *hsv = GTK_HSV (widget);
   GtkHSVPrivate *priv = hsv->priv;
+  gboolean draw_focus;
+
+  draw_focus = gtk_widget_has_visible_focus (widget);
 
   paint_ring (hsv, cr);
-  paint_triangle (hsv, cr);
+  paint_triangle (hsv, cr, draw_focus);
+
 
-  if (gtk_widget_has_focus (widget) && priv->focus_on_ring)
+  if (draw_focus && priv->focus_on_ring)
     {
       GtkStyleContext *context;
       GtkStateFlags state;
index 456e4efdf3c7c5f10e825694b7a083b705809855..fe8ccb326fffb1e91b4f8bc7c6f58145c88093d2 100644 (file)
@@ -1589,7 +1589,7 @@ gtk_icon_view_draw (GtkWidget *widget,
   cairo_save (cr);
 
   gtk_cairo_transform_to_window (cr, widget, icon_view->priv->bin_window);
-      
+
   cairo_set_line_width (cr, 1.);
 
   gtk_icon_view_get_drag_dest_item (icon_view, &path, &dest_pos);
@@ -1602,7 +1602,7 @@ gtk_icon_view_draw (GtkWidget *widget,
   else
     dest_index = -1;
 
-  for (icons = icon_view->priv->items; icons; icons = icons->next) 
+  for (icons = icon_view->priv->items; icons; icons = icons->next)
     {
       GtkIconViewItem *item = icons->data;
       GdkRectangle paint_area;
@@ -1621,8 +1621,8 @@ gtk_icon_view_draw (GtkWidget *widget,
         {
           gtk_icon_view_paint_item (icon_view, cr, item,
                                     ((GdkRectangle *)item)->x, ((GdkRectangle *)item)->y,
-                                    icon_view->priv->draw_focus); 
-     
+                                    icon_view->priv->draw_focus);
+
           if (dest_index == item->index)
             dest_item = item;
         }
@@ -1677,7 +1677,7 @@ gtk_icon_view_draw (GtkWidget *widget,
                         rect.x, rect.y,
                         rect.width, rect.height);
     }
-  
+
   if (icon_view->priv->doing_rubberband)
     gtk_icon_view_paint_rubberband (icon_view, cr);
 
index 0b7ee8833235b8391f193fb5aa8cd15b389fd246..6a6f72cf0aea2ef3487cdba89bf4b985fc9f8685 100644 (file)
@@ -4209,7 +4209,6 @@ gtk_label_draw (GtkWidget *widget,
           focus_link = gtk_label_get_focus_link (label);
           active_link = info->active_link;
 
-
           if (active_link)
             {
               GdkRGBA bg_color;
@@ -4253,7 +4252,7 @@ gtk_label_draw (GtkWidget *widget,
               cairo_restore (cr);
             }
 
-          if (focus_link && gtk_widget_has_focus (widget))
+          if (focus_link && gtk_widget_has_visible_focus (widget))
             {
               range[0] = focus_link->start;
               range[1] = focus_link->end;
index f26a9f53cd8dbd9b4ff654b13d43d98100f126a2..a0ca89dfb5e3c084fd15c9d01d3e16eaeba11448 100644 (file)
@@ -1845,6 +1845,17 @@ gtk_main_do_event (GdkEvent *event)
             break;
         }
 
+      /* make focus visible in a window that receives a key event */
+      {
+        GtkWidget *window;
+        GtkPolicyType visible_focus;
+
+        window = gtk_widget_get_toplevel (grab_widget);
+        g_object_get (gtk_widget_get_settings (grab_widget), "gtk-visible-focus", &visible_focus, NULL);
+        if (GTK_IS_WINDOW (window) && visible_focus != GTK_POLICY_NEVER)
+          gtk_window_set_focus_visible (GTK_WINDOW (window), TRUE);
+      }
+
       /* Catch alt press to enable auto-mnemonics;
        * menus are handled elsewhere
        * FIXME: this does not work with mnemonic modifiers other than Alt
@@ -1866,7 +1877,6 @@ gtk_main_do_event (GdkEvent *event)
               mnemonics_visible = (event->type == GDK_KEY_PRESS);
 
               window = gtk_widget_get_toplevel (grab_widget);
-
               if (GTK_IS_WINDOW (window))
                 gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible);
             }
index 8cf23c40c38becfe94dda1bd648fd39429877035..cd191756311452d25600afb9b4ed3b89dbe78752 100644 (file)
@@ -5255,7 +5255,7 @@ gtk_notebook_draw_tab (GtkNotebook     *notebook,
                        page->allocation.height,
                        get_tab_gap_pos (notebook));
 
-  if (gtk_widget_has_focus (widget) &&
+  if (gtk_widget_has_visible_focus (widget) &&
       priv->cur_page == page)
     {
       gint focus_width, focus_pad;
index 2e4331610d37668f14d2bc6b9f32139782ab3900..96e54c6668c0e7239f8cc3280219dc11420f586f 100644 (file)
@@ -2194,7 +2194,7 @@ gtk_range_draw (GtkWidget *widget,
 
       gtk_style_context_restore (context);
 
-      if (sensitive && gtk_widget_has_focus (widget))
+      if (sensitive && gtk_widget_has_visible_focus (widget))
         {
           gtk_style_context_save (context);
           gtk_style_context_set_state (context,
index ba24502fc7b3ef81d820a5e101f7aede49bad29c..ab5c5aa960f95519e221ac10e233a3ddfebaf369 100644 (file)
@@ -178,6 +178,7 @@ enum {
   PROP_TOOLBAR_STYLE,
   PROP_TOOLBAR_ICON_SIZE,
   PROP_AUTO_MNEMONICS,
+  PROP_VISIBLE_FOCUS,
   PROP_APPLICATION_PREFER_DARK_THEME,
   PROP_BUTTON_IMAGES,
   PROP_ENTRY_SELECT_ON_FOCUS,
@@ -1113,6 +1114,24 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                              NULL);
   g_assert (result == PROP_AUTO_MNEMONICS);
 
+  /**
+   * GtkSettings:gtk-visible-focus:
+   *
+   * Whether 'focus rectangles' should be always visible, never visible,
+   * or hidden until the user starts to use the keyboard.
+   *
+   * Since: 3.2
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_enum ("gtk-visible-focus",
+                                                                P_("Visible Focus"),
+                                                                P_("Whether 'focus rectangles' should be hidden until the user starts to use the keyboard."),
+                                                                GTK_TYPE_POLICY_TYPE,
+                                                                GTK_POLICY_ALWAYS,
+                                                                GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_VISIBLE_FOCUS);
+
   /**
    * GtkSettings:gtk-application-prefer-dark-theme:
    *
index 8d9c38aeb72fe6cf3370b9d2ea052d460d9b8b7a..8604079cf064d6a09e92e61911d741df27c0e915 100644 (file)
@@ -570,7 +570,7 @@ gtk_switch_draw (GtkWidget *widget,
   width = gtk_widget_get_allocated_width (widget);
   height = gtk_widget_get_allocated_height (widget);
 
-  if (gtk_widget_has_focus (widget))
+  if (gtk_widget_has_visible_focus (widget))
     gtk_render_focus (context, cr, x, y, width, height);
 
   x += focus_width + focus_pad;
index b722c51d986d74c0c2661e417cf331f63bc936ea..4ddc279e16935f542285b43725b354e9f6c3be7f 100644 (file)
@@ -4906,7 +4906,7 @@ gtk_text_view_draw_focus (GtkWidget *widget,
                        "interior-focus", &interior_focus,
                        NULL);
   
-  if (gtk_widget_has_focus (widget) && !interior_focus)
+  if (gtk_widget_has_visible_focus (widget) && !interior_focus)
     {
       GtkStyleContext *context;
 
index 3dd5129d293295a14571d6642f206b4fa5f2f0e7..9c35dafd70389116cadbb0238bed76d0ac650a85 100644 (file)
@@ -387,7 +387,7 @@ gtk_tray_icon_draw (GtkWidget *widget,
     retval = GTK_WIDGET_CLASS (gtk_tray_icon_parent_class)->draw (widget, cr);
 
   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (widget));
-  if (focus_child && gtk_widget_has_focus (focus_child))
+  if (focus_child && gtk_widget_has_visible_focus (focus_child))
     {
       GtkStyleContext *context;
       GtkStateFlags state;
index 494d4ad522bd9dc136355c61cfb736999435f4b6..36d1bb258c31a4b814edeb690285724ab9f34bf3 100644 (file)
@@ -4519,7 +4519,7 @@ draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
   GtkWidget *widget = GTK_WIDGET (tree_view);
   gint w, h;
 
-  if (!gtk_widget_has_focus (widget))
+  if (!gtk_widget_has_visible_focus (widget))
     return;
 
   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
@@ -4965,7 +4965,7 @@ gtk_tree_view_bin_draw (GtkWidget      *widget,
          if (node == cursor && has_can_focus_cell
               && ((column == tree_view->priv->focus_column
                    && tree_view->priv->draw_keyfocus &&
-                   gtk_widget_has_focus (widget))
+                   gtk_widget_has_visible_focus (widget))
                   || (column == tree_view->priv->edited_column)))
             draw_focus = TRUE;
           else
@@ -5202,7 +5202,7 @@ gtk_tree_view_bin_draw (GtkWidget      *widget,
       /* draw the big row-spanning focus rectangle, if needed */
       if (!has_can_focus_cell && node == cursor &&
           tree_view->priv->draw_keyfocus &&
-         gtk_widget_has_focus (widget))
+         gtk_widget_has_visible_focus (widget))
         {
          gint tmp_y, tmp_height;
          GtkStateFlags focus_rect_state = 0;
index a84f31c881ed7a860356807f05f534d4af7ace5e..95422621b8d274e3bf65af192441c397211c5767 100644 (file)
@@ -6681,6 +6681,48 @@ gtk_widget_has_focus (GtkWidget *widget)
   return widget->priv->has_focus;
 }
 
+/**
+ * gtk_widget_has_visible_focus:
+ * @widget: a #GtkWidget
+ *
+ * Determines if the widget should show a visible indication that
+ * it has the global input focus. This is a convenience function for
+ * use in ::draw handlers that takes into account whether focus
+ * indication should currently be shown in the toplevel window of
+ * @widget. See gtk_window_get_focus_visible() for more information
+ * about focus indication.
+ *
+ * To find out if the widget has the global input focus, use
+ * gtk_widget_has_focus().
+ *
+ * Return value: %TRUE if the widget should display a 'focus rectangle'
+ *
+ * Since: 3.2
+ */
+gboolean
+gtk_widget_has_visible_focus (GtkWidget *widget)
+{
+  gboolean draw_focus;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  if (widget->priv->has_focus)
+    {
+      GtkWidget *toplevel;
+
+      toplevel = gtk_widget_get_toplevel (widget);
+
+      if (GTK_IS_WINDOW (toplevel))
+        draw_focus = gtk_window_get_focus_visible (GTK_WINDOW (toplevel));
+      else
+        draw_focus = TRUE;
+    }
+  else
+    draw_focus = FALSE;
+
+  return draw_focus;
+}
+
 /**
  * gtk_widget_is_focus:
  * @widget: a #GtkWidget
index 4694ffa1afa0f610380c1654a809c8f19d3eb38d..ead01ed4d1d5ec702012e79d6497f0f7ee7ee3d8 100644 (file)
@@ -560,6 +560,7 @@ void       gtk_widget_set_can_focus       (GtkWidget           *widget,
 gboolean   gtk_widget_get_can_focus       (GtkWidget           *widget);
 gboolean   gtk_widget_has_focus           (GtkWidget           *widget);
 gboolean   gtk_widget_is_focus            (GtkWidget           *widget);
+gboolean   gtk_widget_has_visible_focus   (GtkWidget           *widget);
 void       gtk_widget_grab_focus          (GtkWidget           *widget);
 
 void       gtk_widget_set_can_default     (GtkWidget           *widget,
index 3eb31054e7856d9586c45fcdb7df8db054634c60..e281d6e081206ff07dccaaf8f0f53c8fa60ee9d3 100644 (file)
@@ -157,6 +157,7 @@ struct _GtkWindowPrivate
   guint    maximize_initially        : 1;
   guint    mnemonics_visible         : 1;
   guint    mnemonics_visible_set     : 1;
+  guint    focus_visible             : 1;
   guint    modal                     : 1;
   guint    opacity_set               : 1;
   guint    position                  : 3;
@@ -225,11 +226,12 @@ enum {
   /* Readonly properties */
   PROP_IS_ACTIVE,
   PROP_HAS_TOPLEVEL_FOCUS,
-  
+
   /* Writeonly properties */
   PROP_STARTUP_ID,
-  
+
   PROP_MNEMONICS_VISIBLE,
+  PROP_FOCUS_VISIBLE,
 
   LAST_ARG
 };
@@ -702,6 +704,18 @@ gtk_window_class_init (GtkWindowClass *klass)
                                                         P_("Icon for this window"),
                                                         GDK_TYPE_PIXBUF,
                                                         GTK_PARAM_READWRITE));
+
+  /**
+   * GtkWindow:mnemonics-visible:
+   *
+   * Whether mnemonics are currently visible in this window.
+   *
+   * This property is maintained by GTK+ based on the
+   * #GtkSettings:gtk-auto-mnemonics setting and user input,
+   * and should not be set by applications.
+   *
+   * Since: 2.20
+   */
   g_object_class_install_property (gobject_class,
                                    PROP_MNEMONICS_VISIBLE,
                                    g_param_spec_boolean ("mnemonics-visible",
@@ -709,6 +723,25 @@ gtk_window_class_init (GtkWindowClass *klass)
                                                          P_("Whether mnemonics are currently visible in this window"),
                                                          TRUE,
                                                          GTK_PARAM_READWRITE));
+
+  /**
+   * GtkWindow:focus-visible:
+   *
+   * Whether 'focus rectangles' are currently visible in this window.
+   *
+   * This property is maintained by GTK+ based on the
+   * #GtkSettings:gtk-visible-focus setting and user input
+   * and should not be set by applications.
+   *
+   * Since: 2.20
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_FOCUS_VISIBLE,
+                                   g_param_spec_boolean ("focus-visible",
+                                                         P_("Focus Visible"),
+                                                         P_("Whether focus rectangles are currently visible in this window"),
+                                                         TRUE,
+                                                         GTK_PARAM_READWRITE));
   
   /**
    * GtkWindow:icon-name:
@@ -1112,6 +1145,7 @@ gtk_window_init (GtkWindow *window)
   priv->initial_timestamp = GDK_CURRENT_TIME;
   priv->has_resize_grip = TRUE;
   priv->mnemonics_visible = TRUE;
+  priv->focus_visible = TRUE;
 
   g_object_ref_sink (window);
   priv->has_user_ref_count = TRUE;
@@ -1231,6 +1265,9 @@ gtk_window_set_property (GObject      *object,
     case PROP_MNEMONICS_VISIBLE:
       gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value));
       break;
+    case PROP_FOCUS_VISIBLE:
+      gtk_window_set_focus_visible (window, g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1349,6 +1386,9 @@ gtk_window_get_property (GObject      *object,
     case PROP_MNEMONICS_VISIBLE:
       g_value_set_boolean (value, priv->mnemonics_visible);
       break;
+    case PROP_FOCUS_VISIBLE:
+      g_value_set_boolean (value, priv->focus_visible);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -4675,6 +4715,7 @@ gtk_window_map (GtkWidget *widget)
   GdkWindow *toplevel;
   GdkWindow *gdk_window;
   gboolean auto_mnemonics;
+  GtkPolicyType visible_focus;
 
   gdk_window = gtk_widget_get_window (widget);
 
@@ -4747,7 +4788,7 @@ gtk_window_map (GtkWidget *widget)
       if (priv->startup_id != NULL)
         {
           /* Make sure we have a "real" id */
-          if (!startup_id_is_fake (priv->startup_id)) 
+          if (!startup_id_is_fake (priv->startup_id))
             gdk_notify_startup_complete_with_id (priv->startup_id);
 
           g_free (priv->startup_id);
@@ -4763,10 +4804,21 @@ gtk_window_map (GtkWidget *widget)
   /* if auto-mnemonics is enabled and mnemonics visible is not already set
    * (as in the case of popup menus), then hide mnemonics initially
    */
-  g_object_get (gtk_widget_get_settings (widget), "gtk-auto-mnemonics",
-                &auto_mnemonics, NULL);
+  g_object_get (gtk_widget_get_settings (widget),
+                "gtk-auto-mnemonics", &auto_mnemonics,
+                "gtk-visible-focus", &visible_focus,
+                NULL);
+
   if (auto_mnemonics && !priv->mnemonics_visible_set)
     gtk_window_set_mnemonics_visible (window, FALSE);
+
+  /* inherit from transient parent, so that a dialog that is
+   * opened via keynav shows focus initially
+   */
+  if (priv->transient_parent)
+    gtk_window_set_focus_visible (window, gtk_window_get_focus_visible (priv->transient_parent));
+  else
+    gtk_window_set_focus_visible (window, visible_focus == GTK_POLICY_ALWAYS);
 }
 
 static gboolean
@@ -5983,7 +6035,7 @@ gtk_window_focus_in_event (GtkWidget     *widget,
       if (auto_mnemonics)
         maybe_set_mnemonics_visible (window);
     }
-      
+
   return FALSE;
 }
 
@@ -9486,6 +9538,53 @@ gtk_window_set_mnemonics_visible (GtkWindow *window,
   priv->mnemonics_visible_set = TRUE;
 }
 
+/**
+ * gtk_window_get_focus_visible:
+ * @window: a #GtkWindow
+ *
+ * Gets the value of the #GtkWindow:focus-visible property.
+ *
+ * Returns: %TRUE if 'focus rectangles' are supposed to be visible
+ *     in this window.
+ *
+ * Since: 3.2
+ */
+gboolean
+gtk_window_get_focus_visible (GtkWindow *window)
+{
+  g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+  return window->priv->focus_visible;
+}
+
+/**
+ * gtk_window_set_focus_visible:
+ * @window: a #GtkWindow
+ * @setting: the new value
+ *
+ * Sets the #GtkWindow:focus-visible property.
+ *
+ * Since: 3.2
+ */
+void
+gtk_window_set_focus_visible (GtkWindow *window,
+                              gboolean   setting)
+{
+  GtkWindowPrivate *priv;
+
+  g_return_if_fail (GTK_IS_WINDOW (window));
+
+  priv = window->priv;
+
+  setting = setting != FALSE;
+
+  if (priv->focus_visible != setting)
+    {
+      priv->focus_visible = setting;
+      g_object_notify (G_OBJECT (window), "focus-visible");
+    }
+}
+
 void
 _gtk_window_get_wmclass (GtkWindow  *window,
                          gchar     **wmclass_name,
index 2752d8daed89abdbca605e4f9a0fb716ab57b1eb..d44eedaf7d0e327eb93f047bb95a0879677ad2fe 100644 (file)
@@ -162,6 +162,9 @@ gboolean   gtk_window_get_destroy_with_parent  (GtkWindow           *window);
 void       gtk_window_set_mnemonics_visible    (GtkWindow           *window,
                                                 gboolean             setting);
 gboolean   gtk_window_get_mnemonics_visible    (GtkWindow           *window);
+void       gtk_window_set_focus_visible        (GtkWindow           *window,
+                                                gboolean             setting);
+gboolean   gtk_window_get_focus_visible        (GtkWindow           *window);
 
 void       gtk_window_set_resizable            (GtkWindow           *window,
                                                 gboolean             resizable);